package com.lgmshare.component.downloader;

import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.lgmshare.component.utils.FileUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by heavyrainlee on 20/02/2018.
 */
public class SimpleFileDownloader {

    private static SimpleFileDownloader sDownloader;

    private final OkHttpClient mOkHttpClient;

    public static SimpleFileDownloader get() {
        if (sDownloader == null) {
            sDownloader = new SimpleFileDownloader();
        }
        return sDownloader;
    }

    private SimpleFileDownloader() {
        mOkHttpClient = new OkHttpClient();
    }

    /**
     * @param url
     * @param saveDir  沙盒下目录文件夹（android Q文件系统更改）
     * @param listener
     */
    public void start(final String url, final String saveDir, final OnFileDownloadListener listener) {
        start(url, saveDir, null, listener);
    }

    /**
     * @param url
     * @param saveDir  下载文件保存的文件路径
     *                 Android Q 文件系统更改,saveDir应该是沙盒下目录文件夹
     * @param saveName 下载文件保存的文件名
     * @param listener 在主线程中回调
     */
    public void start(final String url, final String saveDir, final String saveName, final OnFileDownloadListener listener) {
        if (listener != null) {
            listener.onStart();
        }
        if (TextUtils.isEmpty(url)) {
            sendFailureResultCallback("url is null", listener);
            return;
        }
        if (TextUtils.isEmpty(saveDir)) {
            sendFailureResultCallback("saveDir is null", listener);
            return;
        }
        Request request = new Request.Builder().url(url).build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 下载失败
                if (call.isCanceled()) {
                    sendCancelResultCallback(listener);
                } else {
                    sendFailureResultCallback(e.getMessage(), listener);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求取消
                if (call.isCanceled()) {
                    sendCancelResultCallback(listener);
                    return;
                }
                InputStream is = null;
                OutputStream os = null;
                // 储存下载文件的目录
                String fileDir = isExistDir(saveDir);
                String fileName = TextUtils.isEmpty(saveName) ? getNameFromUrl(url) : saveName;
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    File file = new File(fileDir, fileName);
                    os = new FileOutputStream(file);
                    byte[] buf = new byte[2048];
                    int len = 0;
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        os.write(buf, 0, len);
                        sum += len;
                        // 下载中
                        sendProgressCallback(total, sum, len, listener);
                    }
                    os.flush();
                    // 下载完成
                    sendSuccessResultCallback(file, listener);
                } catch (Exception e) {
                    File file = new File(fileDir, fileName);
                    if (file.exists()) {
                        file.delete();
                    }
                    //下载失败
                    sendFailureResultCallback(e.getMessage(), listener);
                } finally {
                    FileUtils.closeIO(is, os);
                }
            }
        });
    }

    public void cancel() {
        mOkHttpClient.cache();
    }

    /**
     * @param dir 沙盒目录下文件夹
     * @return
     * @throws IOException 判断下载目录是否存在
     */
    private String isExistDir(String dir) throws IOException {
        // 下载位置
        File fileDir = new File(dir);
        if (!fileDir.mkdirs()) {
            fileDir.createNewFile();
        }
        return fileDir.getAbsolutePath();
    }

    /**
     * @param url
     * @return 从下载连接中解析出文件名
     */
    @NonNull
    private String getNameFromUrl(String url) {
        return FileUtils.getFileName(url);
    }

    private void sendCancelResultCallback(final OnFileDownloadListener listener) {
        if (listener != null) {
            listener.onFinish();
            listener.onCancel();
        }
    }

    private void sendProgressCallback(final long total, final long currentSize, final long offset, final OnFileDownloadListener listener) {
        if (listener != null) {
            listener.onProgress(total, currentSize, offset);
        }
    }

    private void sendSuccessResultCallback(final File file, final OnFileDownloadListener listener) {
        if (listener != null) {
            listener.onFinish();
            listener.onSuccess(file);
        }
    }

    private void sendFailureResultCallback(final String errorMsg, final OnFileDownloadListener listener) {
        if (listener != null) {
            listener.onFinish();
            listener.onFailure(errorMsg);
        }
    }

    public interface OnFileDownloadListener {

        /**
         * 请求开始
         */
        void onStart();

        /**
         * 请求结束
         */
        void onFinish();

        /**
         * 请求取消
         */
        void onCancel();

        /**
         * 下载进度
         *
         * @param totalSize   文件大小
         * @param currentSize 下载进度
         * @param offset      下载速度
         */
        void onProgress(long totalSize, long currentSize, long offset);

        /**
         * 下载成功
         */
        void onSuccess(File file);

        /**
         * 下载失败
         */
        void onFailure(String errorMsg);

    }
}